﻿using AgCIM.Tools.Maths.Numerics;
using GMap.NET;
using GMap.NET.MapProviders;
using GMap.NET.Projections;
using GMap.NET.WindowsForms;
using OSGeo.GDAL;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AgCIM.Tools.DP.AgControls.MapLayers
{
    internal class LocalTifProvider : GMapProvider
    {
        public static readonly LocalTifProvider Instance;

        private string _tilePath;
        private System.Guid m_id = Guid.NewGuid();
        private GMapProvider[] _overlays;
        // 使用GDAL对本地的Tiff影像按指定的范围进行切图
        // 假设本地Tiff影像的路径
        private string inputTiffPath = @"F:\项目\2017年\AIndex\无锡影像\江苏影像.tif";
        private OSGeo.GDAL.Dataset inputDataset;
        private BoundingBox2d m_tifBoundingBox = new BoundingBox2d();
        private bool m_isFirstLoad=false;
        private bool m_isLoading = false;
        private List<LocalTifFileGMapImageProxy2> m_queueItems = new List<LocalTifFileGMapImageProxy2>();
        private GMapControl m_mapControl;

        public LocalTifProvider(string tilePath , GMapControl m_2dMap)
        {
            m_mapControl=m_2dMap;
            inputTiffPath = tilePath;
            MaxZoom = 18; // 设置最大缩放级别
            MinZoom = 0;  // 设置最小缩放级别
            _tilePath = Path.GetDirectoryName(inputTiffPath)+"\\"+Path.GetFileNameWithoutExtension(inputTiffPath)+"_cache";
            if(Directory.Exists(_tilePath)==false)
            {
                Directory.CreateDirectory(_tilePath);
            }
        }

        public override Guid Id => m_id;

        public override string Name => Path.GetFileNameWithoutExtension(inputTiffPath);

        public override PureProjection Projection
        {
            get
            {
                return MercatorProjection.Instance;
            }
        }

        public override GMapProvider[] Overlays
        {
            get
            {
                if (_overlays == null)
                {
                    _overlays = new GMapProvider[] { this };
                }

                return _overlays;
            }
        }
        private void FirstLoad()
        { // 引入GDAL库
            if(m_isFirstLoad) return;
            m_isFirstLoad = true;
            OSGeo.GDAL.Gdal.AllRegister();

            // 打开输入的Tiff影像
            inputDataset = OSGeo.GDAL.Gdal.Open(inputTiffPath, OSGeo.GDAL.Access.GA_ReadOnly);
            if (inputDataset == null)
            {
                MessageBox.Show($"无法打开输入的Tiff影像: {inputTiffPath}", "错误");
                return;
            }

            // Get input dataset bounds
            double[] inputGeoTransform = new double[6];
            inputDataset.GetGeoTransform(inputGeoTransform);

            double inputMinX = inputGeoTransform[0];
            double inputMaxY = inputGeoTransform[3];
            double inputMaxX = inputMinX + (inputDataset.RasterXSize * inputGeoTransform[1]);
            double inputMinY = inputMaxY + (inputDataset.RasterYSize * inputGeoTransform[5]);

            m_tifBoundingBox = new BoundingBox2d(inputMinX, inputMaxX, inputMinY, inputMaxY);
        }
        public override void OnInitialized()
        {
            base.OnInitialized();

            System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
            timer.Interval = 300;
            timer.Tick += (sender, e) =>
            {
                lock (m_queueItems)
                {
                    if (m_queueItems.Count > 0&& m_isLoading==false)
                    {
                        m_isLoading=true;
                        var lastItem = m_queueItems.Last();
                        while (IsViewBounds(lastItem) == false)
                        {
                            m_queueItems.Remove(lastItem);
                            if(m_queueItems.Count==0)
                            {
                                m_isLoading=false;
                                return;
                            }
                            lastItem = m_queueItems.Last();
                        }
                        lastItem.Load();
                        m_queueItems.Remove(lastItem);
                        m_isLoading = false;
                    }
                }
            };
            timer.Start();
        }
        public override PureImage GetTileImage(GPoint pos, int zoom)
        {
            if (m_isFirstLoad == false)
            {
                FirstLoad();
            }
            if (inputDataset == null)
            {
                return null;
            }
            var y = Math.Pow(2, zoom);
            string filePath = Path.Combine(
                _tilePath,
                zoom.ToString(),
                pos.X.ToString(),
                (y - pos.Y - 1) + ".png"); // 或.jpg根据实际格式

            if (File.Exists(filePath))
            {
                return new LocalTifFileGMapImageProxy(filePath);
            }
            else 
            {
                var bb = GetTileBounds(pos, zoom);

                // Check if input dataset bounds are within requested bounds
                if (m_tifBoundingBox.MinX > bb.MaxX || m_tifBoundingBox.MaxX < bb.MinX ||
                    m_tifBoundingBox.MinY > bb.MaxY || m_tifBoundingBox.MaxY < bb.MinY)
                {
                    return null;
                }
                lock (m_queueItems)
                {
                    var a = new LocalTifFileGMapImageProxy2(pos, zoom, bb, _tilePath, inputDataset);
                    m_queueItems.Add(a);
                    return a;
                }
            }

            return null;
        }
        /// <summary>
        /// Gets the latitude/longitude bounds of a tile
        /// </summary>
        /// <param name="pos">Tile coordinates</param>
        /// <param name="zoom">Zoom level</param>
        /// <returns>Tuple containing (minLng, minLat, maxLng, maxLat)</returns>
        public BoundingBox2d GetTileBounds(GPoint pos, int zoom)
        {
            var y = Math.Pow(2, zoom);
            var latDif = 360 / y;

            return new BoundingBox2d(pos.X * latDif - 180, (pos.X + 1) * latDif - 180, 180 - (pos.Y + 1) * latDif,
                  180 - pos.Y * latDif);
        }

        public bool IsViewBounds(LocalTifFileGMapImageProxy2 lastItem)
        {
            var brl = this.m_mapControl.ViewArea.Right - this.m_mapControl.ViewArea.Left;
            var btb = this.m_mapControl.ViewArea.Top - this.m_mapControl.ViewArea.Bottom;

            var trl = lastItem.BoundingBox.MaxX - lastItem.BoundingBox.MinX;
            if (trl > 0.01)
            {
                return true;
            }
            var trb = lastItem.BoundingBox.MaxY - lastItem.BoundingBox.MinY;
            if (trb > 0.01)
            {
                return true;
            }

            if (lastItem.BoundingBox.MinX > this.m_mapControl.ViewArea.Right + brl * 0.3)
                return false;
            if (lastItem.BoundingBox.MinY > this.m_mapControl.ViewArea.Top + btb * 0.3)
                return false;
            if (lastItem.BoundingBox.MaxX < this.m_mapControl.ViewArea.Left - brl * 0.3)
                return false;
            if (lastItem.BoundingBox.MaxY < this.m_mapControl.ViewArea.Bottom - btb * 0.3)
                return false;
            return true;
        }
    }
    public class LocalTifFileGMapImageProxy2 : GMapImage
    {
        private GPoint pos;
        private int zoom;
        private string _tilePath;
        private Dataset inputDataset;
        private BoundingBox2d m_bb;
        private bool m_isLoaded = false;

        public BoundingBox2d BoundingBox { get { return m_bb; } }

        public LocalTifFileGMapImageProxy2(GPoint pos, int zoom,BoundingBox2d bb,
            string _tilePath, Dataset inputDataset)
        {
            this.pos=new GPoint(pos.X, pos.Y);
            this.zoom=zoom;
            this.m_bb = bb;
            this._tilePath = _tilePath;
            this.inputDataset = inputDataset;
        }
        public void Load()
        {
            if (m_isLoaded) return;
            m_isLoaded = true;
            var tile = GetTile(pos, zoom);
            if (tile == null)
            {
                return;
            }
            try
            {
                var image = System.Drawing.Image.FromFile(tile);

                MemoryStream ms = new MemoryStream();
                image.Save(ms, image.RawFormat);
                ms.Position = 0;
                this.Data = ms;

                this.Img = image;
            }
            catch (Exception ex)
            {
                //File.Delete(filePath);
            }
        }
        public string GetTile(GPoint pos, int zoom)
        {
            // 定义输出切图的路径
            var y = Math.Pow(2, zoom);
            var y2 = y - pos.Y - 1;

            var imageDir = $"{zoom}\\{pos.X}\\{y2}.tif";
            string outputTiffPath = Path.Combine(_tilePath, imageDir);
            string outputImagePath = Path.ChangeExtension(outputTiffPath, ".PNG");
            if (File.Exists(outputImagePath))
            {
                return outputImagePath;
            }
            try
            {
                if (Directory.Exists(Path.GetDirectoryName(outputTiffPath)) == false)
                {
                    Directory.CreateDirectory(Path.GetDirectoryName(outputTiffPath));
                }

                if (inputDataset != null)
                {
                    var op = new GDALWarpAppOptions(new string[] {
                        "-te",  m_bb.MinX.ToString(), m_bb.MinY.ToString(), m_bb.MaxX.ToString(),  m_bb.MaxY.ToString(),
                        "-te_srs", "EPSG:4326",
                        "-ts","256","256",
                        "-dstalpha",
                        "dstAlpha=False",
                        "-co", "PHOTOMETRIC=RGBA",  // 确保输出为RGB彩色
                        "-co", "ALPHA=NO",
                        "-co", "COMPRESS=JPEGS",
                        "-b","1",
                        "-b","2",
                        "-b","3",
                        "-ot", "Int32"
                    });
                    // 根据范围切图
                    OSGeo.GDAL.Dataset outputDataset = OSGeo.GDAL.Gdal.Warp(outputTiffPath,
                        new OSGeo.GDAL.Dataset[] { inputDataset }, op, null, null);

                    if (outputDataset == null)
                    {
                        MessageBox.Show($"切图失败: {OSGeo.GDAL.Gdal.GetLastErrorMsg()}", "错误");
                        return null;
                    }
                   
                    try
                    {
                        // 导出为PNG图片
                        OSGeo.GDAL.Driver driver = OSGeo.GDAL.Gdal.GetDriverByName("PNG");
                        if (driver != null)
                        {
                            string[] pngOptions = new string[] { "WORLDFILE=YES",
                                    "ZLEVEL="+(zoom-2),
                                    "ALPHA=YES"};
                            using (var outputImageDataset = driver.CreateCopy(outputImagePath, outputDataset, 0, null, null, null))
                            {
                                return outputImagePath;
                            }
                        }
                    }
                    catch (Exception err2)
                    {
                        //MessageBox.Show($"图片没有导出到: {outputImagePath}:{err2.Message}", "错误");
                    }
                    finally
                    {
                        outputDataset.Dispose();
                    }
                }
            }
            catch (Exception err)
            {
                MessageBox.Show($"图片没有导出到: {outputTiffPath}:{err.Message}", "错误");
            }
            return null;
        }
        public override void Dispose()
        {
            this.Data.Dispose();
        }
    }
}
